package com.music.note_android.ui.editor

/**
 * 笔画点数据模型
 * 存储笔画路径上单个点的所有信息，包括坐标、压感、时间戳等
 */
data class StrokePoint(
    /**
     * 点的X坐标（画布坐标系）
     */
    val x: Float,
    
    /**
     * 点的Y坐标（画布坐标系）
     */
    val y: Float,
    
    /**
     * 压感值（0.0-1.0）
     * 0.0表示最轻的触摸，1.0表示最重的触摸
     * 对于不支持压感的设备，默认为1.0
     */
    val pressure: Float,
    
    /**
     * 点的创建时间戳（毫秒）
     * 用于计算绘制速度和时间间隔
     */
    val timestamp: Long,
    
    /**
     * 触摸面积大小（可选）
     * 用于在不支持压感的设备上模拟压感效果
     */
    val size: Float = 0f,
    
    /**
     * 点的倾斜角度（可选，弧度制）
     * 用于支持倾斜感应的设备（如Apple Pencil）
     */
    val tilt: Float = 0f,
    
    /**
     * 点的方向角度（可选，弧度制）
     * 用于支持方向感应的设备
     */
    val orientation: Float = 0f
) {
    
    /**
     * 计算到另一个点的距离
     */
    fun distanceTo(other: StrokePoint): Float {
        val dx = x - other.x
        val dy = y - other.y
        return kotlin.math.sqrt(dx * dx + dy * dy)
    }
    
    /**
     * 计算到指定坐标的距离
     */
    fun distanceTo(targetX: Float, targetY: Float): Float {
        val dx = x - targetX
        val dy = y - targetY
        return kotlin.math.sqrt(dx * dx + dy * dy)
    }
    
    /**
     * 计算与另一个点的时间间隔（毫秒）
     */
    fun timeDeltaTo(other: StrokePoint): Long {
        return kotlin.math.abs(timestamp - other.timestamp)
    }
    
    /**
     * 计算相对于另一个点的速度（像素/毫秒）
     */
    fun velocityTo(other: StrokePoint): Float {
        val distance = distanceTo(other)
        val timeDelta = timeDeltaTo(other)
        
        return if (timeDelta > 0) {
            distance / timeDelta
        } else {
            0f
        }
    }
    
    /**
     * 获取标准化的压感值
     * 确保压感值在有效范围内
     */
    fun getNormalizedPressure(): Float {
        return pressure.coerceIn(0f, 1f)
    }
    
    /**
     * 判断是否为有效的压感值
     */
    fun hasValidPressure(): Boolean {
        return pressure in 0f..1f
    }
    
    /**
     * 创建插值点
     * 在当前点和目标点之间创建一个插值点
     * @param other 目标点
     * @param t 插值参数（0.0-1.0）
     */
    fun interpolate(other: StrokePoint, t: Float): StrokePoint {
        val clampedT = t.coerceIn(0f, 1f)
        
        return StrokePoint(
            x = x + (other.x - x) * clampedT,
            y = y + (other.y - y) * clampedT,
            pressure = pressure + (other.pressure - pressure) * clampedT,
            timestamp = timestamp + ((other.timestamp - timestamp) * clampedT).toLong(),
            size = size + (other.size - size) * clampedT,
            tilt = interpolateAngle(tilt, other.tilt, clampedT),
            orientation = interpolateAngle(orientation, other.orientation, clampedT)
        )
    }
    
    /**
     * 角度插值（处理角度的周期性）
     */
    private fun interpolateAngle(angle1: Float, angle2: Float, t: Float): Float {
        val diff = angle2 - angle1
        val adjustedDiff = when {
            diff > kotlin.math.PI -> diff - 2 * kotlin.math.PI
            diff < -kotlin.math.PI -> diff + 2 * kotlin.math.PI
            else -> diff
        }
        return angle1 + adjustedDiff.toFloat() * t
    }
    
    /**
     * 创建平移后的点
     */
    fun translate(dx: Float, dy: Float): StrokePoint {
        return copy(x = x + dx, y = y + dy)
    }
    
    /**
     * 创建缩放后的点
     */
    fun scale(scaleX: Float, scaleY: Float, pivotX: Float = 0f, pivotY: Float = 0f): StrokePoint {
        return copy(
            x = pivotX + (x - pivotX) * scaleX,
            y = pivotY + (y - pivotY) * scaleY
        )
    }
    
    /**
     * 创建旋转后的点
     */
    fun rotate(angle: Float, pivotX: Float = 0f, pivotY: Float = 0f): StrokePoint {
        val cos = kotlin.math.cos(angle)
        val sin = kotlin.math.sin(angle)
        
        val dx = x - pivotX
        val dy = y - pivotY
        
        return copy(
            x = pivotX + (dx * cos - dy * sin).toFloat(),
            y = pivotY + (dx * sin + dy * cos).toFloat(),
            orientation = orientation + angle
        )
    }
    
    /**
     * 判断点是否在指定矩形区域内
     */
    fun isInBounds(left: Float, top: Float, right: Float, bottom: Float): Boolean {
        return x >= left && x <= right && y >= top && y <= bottom
    }
    
    /**
     * 获取点的简要描述，用于调试
     */
    override fun toString(): String {
        return "StrokePoint(x=${String.format("%.2f", x)}, y=${String.format("%.2f", y)}, " +
                "pressure=${String.format("%.3f", pressure)}, timestamp=$timestamp)"
    }
    
    companion object {
        /**
         * 创建默认的笔画点
         */
        fun createDefault(x: Float, y: Float): StrokePoint {
            return StrokePoint(
                x = x,
                y = y,
                pressure = 1.0f,
                timestamp = System.currentTimeMillis()
            )
        }
        
        /**
         * 从触摸事件创建笔画点
         */
        fun fromMotionEvent(
            x: Float,
            y: Float,
            pressure: Float,
            size: Float = 0f,
            orientation: Float = 0f
        ): StrokePoint {
            return StrokePoint(
                x = x,
                y = y,
                pressure = pressure.coerceIn(0f, 1f),
                timestamp = System.currentTimeMillis(),
                size = size,
                orientation = orientation
            )
        }
        
        /**
         * 计算多个点的中心点
         */
        fun calculateCenter(points: List<StrokePoint>): StrokePoint? {
            if (points.isEmpty()) return null
            
            var sumX = 0f
            var sumY = 0f
            var sumPressure = 0f
            var minTimestamp = Long.MAX_VALUE
            
            points.forEach { point ->
                sumX += point.x
                sumY += point.y
                sumPressure += point.pressure
                minTimestamp = minOf(minTimestamp, point.timestamp)
            }
            
            val count = points.size
            return StrokePoint(
                x = sumX / count,
                y = sumY / count,
                pressure = sumPressure / count,
                timestamp = minTimestamp
            )
        }
    }
}